//
//  TempClipFileManager.swift
//  ANOASTORE
//
//  Created by hudan on 2025/5/23.
//  Copyright © 2025 zwb. All rights reserved.
//

// 切片上传

import Foundation

class TempClipFileManager {
    
    static let shared = TempClipFileManager()
    
    private init() {}
    
    /**
     1. 进行切片
     2. 写入数据库
     3. 开始按顺序上传
     4. 同一个切片失败 5 次不再继续上传
     5. 上传成功移除数据库对应记录
     
     - Parameters: 上传文件:(图片, 视频, pdf)
     - files:  文件
     - retryTimes:  失败重试次数
     - complete: finish: true 完成上传, false 未完成上传,下次进入继续重传
     */
    
    public func uploadFile(files: [VideoImg], retryTimes: Int = 5, vouId: String, pic_data: String, pic_data_details: String, templateData: String, menu_nm: String, success: @escaping (() -> Void), error: @escaping ((KSNetworkError) -> Void)) {
        
        self.files = files
        self.retryCount = retryTimes
        self.vouId = vouId
        self.picData = pic_data
        self.templateData = templateData
        self.picDataDetails = pic_data_details
        self.menuName = menu_nm
        self.successBlock = success
        self.errorBlock = error
        
        self.readyToUploadFile()
        
        self.upload()
    }
    
    private var files = [VideoImg]()
    
    private var retryCount = 5
    
    private var vouId: String?
    
    private var picData: String?
        
    private var templateData: String?
    
    private var picDataDetails: String?
    
    private var menuName: String?
    
    private var successBlock: (() -> Void)?
    
    private var errorBlock: ((KSNetworkError) -> Void)?
    
    private var uploadFiles: [VideoImg]?
    
    /// 当前重试次数
    private var currRetryTimes = 0
    
    /// 第一片切片是否上传成功, 用于后面的切片上传是否显示 loading 动画
    private var firstSuccess = false
    
    // 1. 进行切片
    // 2. 写入数据库
    private func readyToUploadFile() {
        
        firstSuccess = false
        
        let clipLength: Int = (USERINFO.clipSize ?? 100)*1024
        
        var uploadFiles = [VideoImg]()
                
        for (idx, file) in files.enumerated() {
            
            let tmpClipFiles = fileToClip(mediaFile: file, index: idx + 1, clipLength: clipLength)
            
            for (_, subClip) in tmpClipFiles.enumerated() {
                
                let params = [(OutlineDBKey.kVouId,          self.vouId.unwrap),
                              (OutlineDBKey.kOfflineDt,      Date.nowTimeToSecond),
                              (OutlineDBKey.kTemplateData,   self.templateData.unwrap),
                              (OutlineDBKey.kPicData,        self.picData.unwrap),
                              (OutlineDBKey.kPicDataDetails, self.picDataDetails.unwrap),
                              (OutlineDBKey.kImgName,        subClip.name.unwrap),
                              (OutlineDBKey.kImgData,        subClip.data!),
                              (OutlineDBKey.kUpStatus,       "0"),
                              (OutlineDBKey.kClipNum,        subClip.clipCount.unwrap),
                              (OutlineDBKey.kClipName,       subClip.clipName.unwrap),
                              (OutlineDBKey.kXuHao,          subClip.clipIndex.unwrap),
                              (OutlineDBKey.kClipFolder,     subClip.clipFolder.unwrap),
                              (OutlineDBKey.kFailReason,     ""),
                              (OutlineDBKey.kMenuName,       self.menuName.unwrap)] as [(String, Any)]
                
                let insertId = FMDBHelper.shared.insertInto(table: OutlineDBKey.TableName, paramValues: params)
                    
                if insertId != nil {
                    var waitUploadFile = subClip
                    waitUploadFile.idkey = insertId.unwrap
                    uploadFiles.append(waitUploadFile)
                    KSLog("插入成功!")
                }
            }
        }
        
        self.uploadFiles = uploadFiles
    }
    
    // 3. 开始按顺序上传
    private func upload() {
        
        guard let files = uploadFiles else {
            // 没有文件, 说明传完了
            self.successBlock?()
            return
        }
        
        // 需要按顺序上传, 所以每次去数组里的第一个
        guard let file = files.first else {
            // 没有文件, 说明传完了
            self.successBlock?()
            return
        }
        
        print("======fileName:\(file.clipName.unwrap)")
        
        uploadOneClip(file: file) { [weak self] err in
            if err == nil {
                
                // 需求: 第一个切片传完就要显示完成, 剩下的后台默默上传, 所以在完成一次调用 successBlock 后置空 block
                if self?.successBlock != nil {
                    self?.successBlock?()
                    self?.successBlock = nil
                }
                
                self?.firstSuccess = true
                
                self?.currRetryTimes = 0
                self?.uploadFiles?.removeFirst()
                
                KSLog("======files: \(self?.uploadFiles ?? [])")
                
                // 5. 上传成功移除数据库对应记录
                ClipOfflineTool.shared.updateUpSatatus(id: file.idkey.unwrap, status: "1")
                
            } else {
                self?.currRetryTimes += 1
                // 4 次重传失败就不再上传, 继续下一个切片
                if self?.currRetryTimes ?? 0 > 5 {
                    
                    // 一片失败太多次,跳过它继续下一片直到所有切片都试了一遍
                    ClipOfflineTool.shared.updateError(id: file.idkey.unwrap, reason: (err != nil ? err!.localizedDescription : "未知错误~"))
                    
                    self?.currRetryTimes = 0
                    self?.uploadFiles?.removeFirst()
                }
            }
            
            self?.upload()
        }
        
    }
    
    private func uploadOneClip(file: VideoImg, complete: @escaping ((_ err: KSNetworkError?) -> Void)) {
        KSNetwork.shared.doRequest(API.temp(.tempUploadFileClipApi(file_name: file.name.unwrap, clip_num: file.clipCount.unwrap, xuhao: file.clipIndex.unwrap, pic_data: self.picData.unwrap, pic_data_details: self.picDataDetails.unwrap, templateData: self.templateData.unwrap, file: file, clip_name: file.clipFolder.unwrap)), showHud: !firstSuccess, successHandle: { (data:BaseResult<OperateResult>) in
            
            if data.flag == TRUE {
                
                complete(nil)
                
            } else {
                complete(.businessFailure(data.errorCombine.unwrap))
            }
            
        }) { kserror in
            
            complete(kserror)
        }
    }
    
    
    
    private func fileToClip(mediaFile: VideoImg, index: Int, clipLength: Int) -> [VideoImg] {
        var name = mediaFile.name.unwrap
        var typeStr = ".jpg"
        var folderName = ""
        
        let formatResult = FileCacheTool.formatFileName(name: name)
        name = formatResult.0
        typeStr = formatResult.1
        folderName = formatResult.2 + "\(index)"
        
        let fileName = "\(name)\(typeStr)"
        
        // 写入磁盘
        FileCacheTool.saveFile(fileData: mediaFile.data, fileName: fileName)
                 
        // 切片
        if mediaFile.data?.count ?? 0 > clipLength {
            var tmpImages = [VideoImg]()
            
            let dataLength = mediaFile.data!.count
            var index = 0
            var lastOffset = 0
            
            while lastOffset < dataLength {
                
                index += 1
                
                var subImage = VideoImg()
                subImage.type = mediaFile.type
                subImage.name = fileName
                subImage.clipName = "\(name)_\(index)\(typeStr)"
                subImage.clipIndex = index
                subImage.clipFolder = folderName
                if lastOffset + clipLength < dataLength {
                    subImage.data = mediaFile.data!.subdata(in: lastOffset..<(lastOffset + clipLength))
                    lastOffset += clipLength
                } else {
                    subImage.data = mediaFile.data!.subdata(in: lastOffset..<dataLength)
                    lastOffset = dataLength
                }
                
                tmpImages.append(subImage)
                
            }
            
            
            var retImages = [VideoImg]()
            
            for subImage in tmpImages {
                var reImage = subImage
                reImage.clipCount = index
                retImages.append(reImage)
            }
            
            return retImages
        } else {
            var retImage = mediaFile
            retImage.name = fileName
            retImage.clipName = "\(name)_1\(typeStr)"
            retImage.clipCount = 1
            retImage.clipIndex = 1
            retImage.clipFolder = folderName
            return [retImage]
        }
    }
}
